home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
comirq.zip
/
COMIRQ.C
next >
Wrap
C/C++ Source or Header
|
1992-12-20
|
5KB
|
244 lines
#if 0
A little program to find all the COM ports on a PC - including ones not
known to the BIOS and then test what IRQ they are using.
If you replace main() with a public function and do something useful instead
of all the printf()'s then it's easily converted into a useful module.
I use Borland C++ compiler.
Roger Barker, December 1992.
CIS 100023,106.
#endif
#include <stdio.h>
#include <dos.h>
typedef void interrupt (INT_FUNC)(void);
typedef unsigned char UCHAR;
typedef struct
{
int addr;
int bios;
} COM_INF;
#define dim(x) (sizeof((x))/sizeof((x)[0]))
#define TRUE 1
#define FALSE 0
#define IRQ3 3
#define IRQ4 4
#define EOI 0x20
#define INTA00 0x20
#define INTA01 0x21
static void UninstallISR(int irq, INT_FUNC *old_func);
static INT_FUNC *InstallISR(int irq, INT_FUNC *service_func);
static void interrupt ServiceIRQ3(void);
static void interrupt ServiceIRQ4(void);
static void CheckCOMsAvailable(void);
static int CheckFitted(int addr);
static COM_INF our_coms[4];
static INT_FUNC *old_irq3;
static INT_FUNC *old_irq4;
static int trigger_3, trigger_4;
void main(void)
{
int i, com, count = 0;
UCHAR old_int, old_modem;
UCHAR old_inta01;
/*
* setup a table in our_coms of all COM ports known to the BIOS and
* also any more that we can find.
*/
CheckCOMsAvailable();
/*
* setup our ISR's and save the original interrupt state.
*/
old_inta01 = inportb(INTA01);
old_irq3 = InstallISR(IRQ3, ServiceIRQ3);
old_irq4 = InstallISR(IRQ4, ServiceIRQ4);
for (i = 0; i < 4 && our_coms[i].addr; i++)
{
com = our_coms[i].addr;
if (our_coms[i].bios)
printf("COM%d is at %3X. ", ++count, com);
else
printf("There is a COM at %3X, the BIOS has not found it. ", com);
/*
* save original state of interrupt enable register and
* enable TX buffer empty interrupt.
*/
old_int = inportb(com+1);
outportb(com+1, 2);
/*
* save original state of modem control register and
* set OUT2 to allow 8250 to generate interrupts.
*/
old_modem = inportb(com+4);
outportb(com+4, 8); /* global interrupt enable */
/*
* clear flags and send a nul. TX buffer interrupt will be generated
* when it has gone.
*/
trigger_3 = trigger_4 = FALSE;
outportb(com,0);
/*
* a little wait. This could fail if the divisor latch is set to
* a totally silly value - may be worth setting it?
*/
delay(500);
/*
* put things back as they were.
*/
outportb(com+1, old_int);
outportb(com+4, old_modem);
/*
* check which IRQ has been triggered. NB this code allows for the
* impossible? situation of both IRQ's being triggered.
*/
if (trigger_3)
printf("It is using IRQ3. \n");
if (trigger_4)
printf("It is using IRQ4.\n");
if (!trigger_3 && !trigger_4)
printf("It is not using IRQ3 or IRQ4\n");
}
/*
* restore the original state of IRQ3, IRQ4 and the 8259 mask.
*/
UninstallISR(IRQ3, old_irq3);
UninstallISR(IRQ4, old_irq4);
outportb(INTA01, old_inta01);
}
static INT_FUNC *InstallISR(int irq, INT_FUNC *service_func)
{
UCHAR mask, inta01_val;
INT_FUNC *old_func;
mask = ~(1 << irq);
old_func = getvect(irq + 8);
setvect(irq+8, service_func);
inta01_val = inportb(INTA01);
outportb(INTA01, mask & inta01_val);
return old_func;
}
static void UninstallISR(int irq, INT_FUNC *old_func)
{
UCHAR mask, inta01_val;
if (!old_func)
return;
mask = 1 << irq;
setvect(irq+8, old_func);
inta01_val = inportb(INTA01);
outportb(INTA01, inta01_val | mask);
}
static void interrupt ServiceIRQ3(void)
{
trigger_3 = TRUE;
outportb(INTA00, EOI);
}
static void interrupt ServiceIRQ4(void)
{
trigger_4 = TRUE;
outportb(INTA00, EOI);
}
/*
* set up in our_coms all the COM ports known to the BIOS and then check
* for any other ports fitted that the BIOS hasn't found.
*/
static void CheckCOMsAvailable(void)
{
int *bioscom = (int *)0x400000;
int i, j, count = 0;
int addr_list[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x3e0, 0x2e0};
/*
* enter all the COMs known to the BIOS into our_coms.
*/
for (i = 0; i < 4 && bioscom[i]; i++)
{
our_coms[count].addr = bioscom[i];
our_coms[count++].bios = TRUE;
}
/*
* now run through our address list and see if there are any more
* COMs that the BIOS hasn't found.
*/
for (i = 0; i < dim(addr_list) && count < 4; i++)
{
/*
* abandon it if it is already in the table.
*/
for (j = 0; j < count; j++)
if (our_coms[j].addr == addr_list[i])
break;
if (j != count)
continue;
if (CheckFitted(addr_list[i]))
{
our_coms[count].addr = addr_list[i];
our_coms[count++].bios = FALSE;
}
}
}
/*
* CheckFitted is partly cribbed from the PC-XT ROM BIOS. It attempts to read
* the interrupt identification register of the 8250. If the chip is there
* then the top 5 bits will be '0'. I have also added a write/read test of
* the line control register. There are surely better ways of finding 8250's!
*/
static int CheckFitted(int addr)
{
UCHAR byte;
int ret;
if (inportb(addr+2) & 0xf8)
return FALSE;
byte = inportb(addr+3); /* save original value */
outportb(addr+3, 0x3f);
ret = (inportb(addr+3) == 0x3f);
outportb(addr+3,byte); /* restore original value */
return ret;
}